package nftrainer;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import language.TextHandler;

import nftrainer.helper.NFMap;
import nftrainer.interfaces.IController;
import nftrainer.taskmanager.TaskManager;
import nftrainer.taskmanager.interfaces.ITaskManager;

public class Controller implements IController {
	
	private ITaskManager taskManager;
	
	private int actualSubtask;
	
	private TextHandler textHandler;
	
	private boolean isStarted = false;
	
	private int points;
	
	@Override
	public void start(TextHandler textHandler) {
		this.taskManager = new TaskManager(textHandler);
		this.taskManager.loadRandomTask();
		this.actualSubtask = 0;
		this.textHandler = textHandler;
		this.isStarted = true;
		this.points = 0;
	}

	@Override
	public String getTask() {
		return this.taskManager.getTaskText();
	}

	@Override
	public String getActualSubtask() {
		if (this.actualSubtask > 5) {
			return this.taskManager.getNextSubtask(5);
		}
		return this.taskManager.getNextSubtask(actualSubtask);
	}

	@Override
	public HashMap<Integer, String[][]> getActualTaskTable() {
		if (actualSubtask < 2) {
			return this.taskManager.getTaskTable();
		} else if (actualSubtask < 5 && actualSubtask > 1) {
			return this.taskManager.getTaskTable1NF();
		} else if (actualSubtask == 5) {
			return this.taskManager.getTaskTables2NF();
		} else if (actualSubtask == 6) {
			return this.taskManager.getTaskTables3NF();
		} else {
			return this.taskManager.getTaskTables3NF();
		}
	}
	
	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public boolean compareUserSolution(Object userSolution) {
		if (userSolution instanceof Boolean) {
			return this.compareFirstSubtaskSolution((Boolean) userSolution);
		} else if (userSolution instanceof List) {
			if (((List) userSolution).size() > 0) {
				if (((List) userSolution).get(0) instanceof NFMap) {
					return this.compareUserSolutionNFMap((List<NFMap>)userSolution);
				} else {
					return this.compareUserSolutionString((List<String>)userSolution);
				}
			}
		}
		return false;
	}
	
	private boolean compareUserSolutionString(List<String> userSolution) {
		Collections.sort(userSolution);
		switch (actualSubtask) {
		case 1:
			return this.taskManager.getNotFirstNFColumns().equals(userSolution);
		case 3:
			return this.taskManager.getPrimaryKey().equals(userSolution);
		default:
			break;
		}
		return false;
	}
	
	private boolean compareUserSolutionNFMap(List<NFMap> userSolution) {
		if (userSolution.size() == 0) {
			return false;
		}
		List<NFMap> check = new ArrayList<NFMap>();
		check.addAll(userSolution);
		
		List<NFMap> actual;
		switch (actualSubtask) {
		case 2:
			actual = this.taskManager.getFunctional();
			break;
		case 4:
			actual = this.taskManager.getSecondNF();
			break;
		case 5:
			actual = this.taskManager.getThirdNF();
			break;
		default:
			return false;
		}
		if (userSolution.size() != actual.size()) {
			return false;
		}
		for (NFMap user : userSolution) {
			for (NFMap solution : actual) {
				if (user.equals(solution)) {
					check.remove(user);
				}
			}
		}
		if (check.size() == 0) {
			return true;
		}
		return false;
	}

	@Override
	public String getSolutionAsString() {
		switch (actualSubtask) {
		case 0:
			if (this.taskManager.isFirstNF()) {
				return textHandler.printf("index.yes");
			} else {
				return textHandler.printf("index.no");
			}
		case 1:
			return this.taskManager.getNotFirstNFColumns().toString().replace("[", "").replace("]", "");
		case 2:
			return this.makeSolutionString(this.taskManager.getFunctional());
		case 3:
			return this.taskManager.getPrimaryKey().toString().replace("[", "").replace("]", "");
		case 4:
			return this.makeSolutionString(this.taskManager.getSecondNF());
		case 5:
			return this.makeSolutionString(this.taskManager.getThirdNF());
		default:
			return "";
		}
	}
	
	private String makeSolutionString(List<NFMap> map) {
		String solution = "";
		for (NFMap m : map) {
			solution+=m.getKeys()+" --> "+m.getValues()+"<br />";
		}
		solution = solution.replace("[", "").replace("]", "");
		return solution;
	}
	
	private void setNextSubtask() {
		this.actualSubtask++;
		if (this.actualSubtask==1 && this.taskManager.isFirstNF()) {
			this.actualSubtask++;
		}
	}

	@Override
	public void next() {
		this.setNextSubtask();
	}

	private boolean compareFirstSubtaskSolution(boolean userSolution) {
		return this.taskManager.isFirstNF() == userSolution;
	}

	@Override
	public boolean taskCompleted() {
		return (this.actualSubtask == taskManager.getSubtaskAmount() ? true : false);
	}

	@Override
	public HashMap<Integer, String[][]> getSolutionTaskTable() {
		if (actualSubtask < 1) {
			return this.taskManager.getTaskTable();
		} else if (actualSubtask < 4 && actualSubtask > 0) {
			return this.taskManager.getTaskTable1NF();
		} else if (actualSubtask == 4) {
			return this.taskManager.getTaskTables2NF();
		} else if (actualSubtask == 5) {
			return this.taskManager.getTaskTables3NF();
		} else {
			return this.taskManager.getTaskTable();
		}
	}

	@Override
	public String getPrimaryKeys() {
		return this.taskManager.getPrimaryKey().toString().replace("[", "").replace("]", "");
	}

	@Override
	public String getFunctional() {
		return this.makeSolutionString(this.taskManager.getFunctional());
	}

	@Override
	public int getActualTaskNumber() {
		return this.actualSubtask;
	}

	@Override
	public boolean isStarted() {
		return this.isStarted;
	}

	@Override
	public void restart() {
		this.isStarted = false;
	}

	@Override
	public void addPoints(int points) {
		this.points+=points;
	}

	@Override
	public int getPoints() {
		return this.points;
	}

}
